"""
学生信息管理系统 - 主程序 (表示层/用户界面层)

📚 教学目标：
1. 理解用户界面设计的重要性
2. 学习程序流程控制和状态管理
3. 掌握用户输入验证和错误处理
4. 了解模块集成和系统架构

🎯 本模块在项目中的作用：
- 提供用户交互界面
- 控制程序主流程
- 处理用户输入和输出
- 集成各个业务模块

⭐ 学习顺序：【第4步】- 最后学习此模块，需要理解前面所有模块

🔗 模块依赖关系：
- 依赖项：student.py (数据模型)、service.py (业务逻辑)
- 被依赖：无(作为程序入口点)

💡 设计原则：
- 单一职责：只负责用户界面和交互
- 用户友好：提供清晰的菜单和错误信息
- 状态管理：维护程序运行状态
- 输入验证：确保用户输入的有效性

🎓 重点概念：
- MVC模式：本模块相当于Controller和View
- 事件循环：主菜单的无限循环直到用户退出
- 异常处理：优雅地处理用户输入错误
- 用户体验：清屏、提示、确认等交互设计
"""

import os  # 💡 用于清屏操作，跨平台兼容
from student import Student  # 💡 导入数据模型
from service import StudentService  # 💡 导入业务逻辑层


class StudentManagementSystem:
    """
    学生信息管理系统主类
    
    🎓 教学要点：
    - 主控制器：协调用户界面和业务逻辑
    - 状态管理：使用self.running控制程序生命周期
    - 组合模式：包含业务服务对象
    - 方法分工：每个方法负责特定的界面功能
    
    💡 设计模式：
    - 门面模式：为用户提供简单的操作界面
    - 控制器模式：处理用户输入，调用相应的业务逻辑
    - 状态模式：维护程序的运行状态
    """

    def __init__(self):
        """
        初始化系统
        
        🎓 教学要点：
        - 依赖注入：创建业务服务对象
        - 状态初始化：设置程序运行标志
        - 职责分离：界面层不直接操作数据库
        
        💡 架构说明：
        - self.service：业务逻辑层的接口
        - self.running：控制主循环的状态变量
        """
        self.service = StudentService()  # 💡 创建业务服务对象，所有业务操作通过它完成
        self.running = True  # 💡 程序运行状态，控制主循环

    def clear_screen(self):
        """
        清屏功能
        
        🎓 教学要点：
        - 跨平台编程：不同操作系统的兼容性处理
        - os.name属性：获取当前操作系统类型
        - os.system()：执行系统命令
        - 用户体验：保持界面整洁
        
        💡 跨平台处理：
        - 'posix'：Unix/Linux/macOS系统，使用'clear'命令
        - 其他（主要是Windows）：使用'cls'命令
        """
        os.system('clear' if os.name == 'posix' else 'cls')  # 💡 根据操作系统执行不同的清屏命令

    def show_menu(self):
        """
        显示主菜单
        
        🎓 教学要点：
        - 用户界面设计：清晰的菜单布局
        - 字符串格式化：使用*操作符重复字符
        - 信息层次：标题、选项、分隔线的视觉层次
        - 用户引导：明确的操作选项和退出方式
        
        💡 界面设计原则：
        - 简洁明了：功能选项一目了然
        - 数字编号：方便用户快速选择
        - 视觉分隔：使用等号线条增强可读性
        - 退出选项：使用0作为退出，符合用户习惯
        """
        print("=" * 30)  # 💡 创建视觉分隔线，增强界面美观度
        print("        学生信息管理系统")  # 💡 系统标题，居中显示
        print("=" * 30)  # 💡 分隔线
        print("1. 添加学生信息")  # 💡 功能选项，使用数字编号便于选择
        print("2. 查询学生信息")
        print("3. 修改学生信息")
        print("4. 删除学生信息")
        print("5. 显示所有学生")
        print("6. 统计信息")  # 💡 统计功能，提供数据分析视图（选做）
        print("0. 退出系统")  # 💡 使用0作为退出选项，符合常见习惯
        print("=" * 30)  # 💡 底部分隔线

    def run(self):
        """
        运行系统
        🎓 教学要点：
        - 主循环：使用while循环保持程序运行
        - 用户输入处理：获取用户选择并调用相应方法
        - 状态管理：使用self.running控制程序的生命周期
        - 错误处理：提供无效输入的反馈
        - 用户体验：清晰的欢迎信息和数据库提示
        💡 程序流程：
        - 显示欢迎信息
        - 进入主循环，显示菜单
        - 根据用户选择调用相应功能
        - 处理用户输入，提供反馈
        - 直到用户选择退出，结束循环并退出程序
        """
        print("欢迎使用学生信息管理系统！")
        print("数据库文件: students.db")

        while self.running:
            self.clear_screen()
            self.show_menu()

            choice = input("\n请选择功能 (0-6): ").strip()

            if choice == '1':
                self.add_student()
            elif choice == '2':
                self.query_student()
            elif choice == '3':
                self.update_student()
            elif choice == '4':
                self.delete_student()
            elif choice == '5':
                self.show_all_students()
            elif choice == '6':
                self.show_statistics()
            elif choice == '0':
                self.running = False
                print("\n谢谢使用，再见！")
            else:
                print("\n无效选择，请重新输入！")
                input("按回车键继续...")

    def input_student_info(self, title="请输入学生信息"):
        """
        输入学生信息
        🎓 教学要点：
        - 用户输入：获取学生的各项信息
        - 输入验证：确保输入的有效性和格式正确
        - 错误处理：使用循环和异常处理确保输入正确
        - 提示信息：清晰的提示用户输入内容
        💡 输入流程：
        - 显示标题
        - 获取学号、姓名、年龄、性别、专业、班级、电话和邮箱
        - 验证年龄为数字，性别只能是男或女
        - 返回一个Student对象，包含所有输入信息
        :param title: 输入信息的标题，默认为"请输入学生信息"
        """
        print(f"\n{title}:")
        print("-" * 30)

        student_id = input("学号: ").strip()
        name = input("姓名: ").strip()

        while True:
            try:
                age = int(input("年龄: ").strip())
                break
            except ValueError:
                print("年龄必须是数字，请重新输入！")

        while True:
            gender = input("性别(男/女): ").strip()
            if gender in ['男', '女']:
                break
            print("性别只能输入'男'或'女'，请重新输入！")

        major = input("专业: ").strip()
        class_name = input("班级: ").strip()
        phone = input("电话(可选): ").strip()
        email = input("邮箱(可选): ").strip()

        return Student(student_id, name, age, gender, major, class_name, phone, email)

    def add_student(self):
        """
        添加学生信息
        🎓 教学要点：
        - 用户输入：获取学生信息并创建Student对象
        - 业务逻辑调用：使用服务层添加学生信息
        - 成功与失败反馈：根据操作结果显示不同的消息
        - 用户体验：清晰的操作提示和结果反馈
        💡 添加流程：
        - 清屏并显示添加学生信息标题
        - 输入学生信息，创建Student对象
        - 调用服务层的add_student方法
        - 根据返回结果显示成功或失败消息

        :return: None
        """
        self.clear_screen()
        print("添加学生信息")

        student = self.input_student_info()
        success, messages = self.service.add_student(student)

        print("\n" + "=" * 30)
        if success:
            print("✓ " + messages[0])
        else:
            print("✗ 添加失败:")
            for message in messages:
                print(f"  - {message}")

        input("\n按回车键继续...")

    def query_student(self):
        """
        查询学生信息
        🎓 教学要点：
        - 用户输入：选择查询方式（学号或姓名）
        - 业务逻辑调用：根据选择调用相应的查询方法
        - 结果展示：显示查询结果或未找到的消息
        - 用户体验：清晰的查询界面和结果反馈
        💡 查询流程：
        - 清屏并显示查询标题
        - 提供查询方式选择（学号或姓名）
        - 根据选择获取学生信息
        - 显示单个学生信息或学生列表
        - 提供返回主菜单的选项

        :return: None
        """
        self.clear_screen()
        print("查询学生信息")
        print("-" * 30)
        print("1. 按学号查询")
        print("2. 按姓名查询")
        print("0. 返回主菜单")

        choice = input("\n请选择查询方式: ").strip()

        if choice == '1':
            student_id = input("请输入学号: ").strip()
            student = self.service.get_student_by_id(student_id)

            if student:
                self.display_student_info(student)
            else:
                print(f"\n未找到学号为 {student_id} 的学生！")

        elif choice == '2':
            name = input("请输入姓名(支持模糊查询): ").strip()
            students = self.service.get_students_by_name(name)

            if students:
                print(f"\n找到 {len(students)} 个匹配的学生:")
                self.display_students_list(students)
            else:
                print(f"\n未找到姓名包含 '{name}' 的学生！")

        elif choice == '0':
            return
        else:
            print("无效选择！")

        input("\n按回车键继续...")

    def update_student(self):
        """
        修改学生信息
        🎓 教学要点：
        - 用户输入：获取要修改的学生学号
        - 业务逻辑调用：查询学生信息并获取修改后的数据
        - 成功与失败反馈：显示修改结果或错误信息
        - 用户体验：清晰的修改界面和结果反馈
        💡 修改流程：
        - 清屏并显示修改标题
        - 输入要修改的学生学号
        - 查询学生信息并显示当前信息
        - 输入新的学生信息，创建Student对象
        - 调用服务层的update_student方法
        - 根据返回结果显示成功或失败消息

        :return: None
        """
        self.clear_screen()
        print("修改学生信息")

        student_id = input("\n请输入要修改的学生学号: ").strip()
        existing_student = self.service.get_student_by_id(student_id)

        if not existing_student:
            print(f"未找到学号为 {student_id} 的学生！")
            input("按回车键继续...")
            return

        print(f"\n当前学生信息:")
        self.display_student_info(existing_student)

        print(f"\n请输入新的学生信息:")
        updated_student = self.input_student_info("修改学生信息")

        success, messages = self.service.update_student(student_id, updated_student)

        print("\n" + "=" * 30)
        if success:
            print("✓ " + messages[0])
        else:
            print("✗ 修改失败:")
            for message in messages:
                print(f"  - {message}")

        input("\n按回车键继续...")

    def delete_student(self):
        """
        删除学生信息
        🎓 教学要点：
        - 用户输入：获取要删除的学生学号
        - 业务逻辑调用：查询学生信息并确认删除
        - 成功与失败反馈：显示删除结果或错误信息
        - 用户体验：清晰的删除界面和结果反馈
        💡 删除流程：
        - 清屏并显示删除标题
        - 输入要删除的学生学号
        - 查询学生信息并显示当前信息
        - 确认删除操作
        - 调用服务层的delete_student方法
        - 根据返回结果显示成功或失败消息

        :return: None
        """
        self.clear_screen()
        print("删除学生信息")

        student_id = input("\n请输入要删除的学生学号: ").strip()
        existing_student = self.service.get_student_by_id(student_id)

        if not existing_student:
            print(f"未找到学号为 {student_id} 的学生！")
            input("按回车键继续...")
            return

        print(f"\n将要删除的学生信息:")
        self.display_student_info(existing_student)

        confirm = input("\n确认删除？(y/N): ").strip().lower()
        if confirm == 'y':
            success, message = self.service.delete_student(student_id)

            print("\n" + "=" * 30)
            if success:
                print("✓ " + message)
            else:
                print("✗ " + message)
        else:
            print("取消删除操作。")

        input("\n按回车键继续...")

    def show_all_students(self):
        """
        显示所有学生信息
        🎓 教学要点：
        - 业务逻辑调用：获取所有学生信息
        - 列表展示：格式化输出学生列表
        - 用户体验：清晰的学生信息展示
        💡 显示流程：
        - 清屏并显示所有学生信息标题
        - 调用服务层的get_all_students方法获取学生列表
        - 如果有学生信息，格式化输出学生列表
        - 如果没有学生信息，显示提示信息
        - 提供返回主菜单的选项
        :return: None
        """

        self.clear_screen()
        print("所有学生信息")

        students = self.service.get_all_students()

        if students:
            print(f"\n共有 {len(students)} 个学生:")
            self.display_students_list(students)
        else:
            print("\n暂无学生信息！")

        input("\n按回车键继续...")

    def display_student_info(self, student):
        """
        显示单个学生信息
        🎓 教学要点：
        - 信息展示：格式化输出学生的详细信息
        - 用户体验：清晰的学生信息展示
        - 数据结构：使用Student对象的属性访问信息
        💡 显示流程：
        - 清屏并显示学生信息标题
        - 打印学生的各项信息
        - 使用格式化字符串对齐输出
        - 提供返回主菜单的选项
        :param student: Student对象
        :return: None
        """
        print("\n" + "=" * 30)
        print(f"学号: {student.student_id}")
        print(f"姓名: {student.name}")
        print(f"年龄: {student.age}")
        print(f"性别: {student.gender}")
        print(f"专业: {student.major}")
        print(f"班级: {student.class_name}")
        print(f"电话: {student.phone}")
        print(f"邮箱: {student.email}")
        print("=" * 30)

    def display_students_list(self, students):
        """
        显示学生列表
        🎓 教学要点：
        - 列表格式化：使用字符串格式化输出学生信息
        - 数据展示：清晰的表格形式展示学生信息
        - 用户体验：易于阅读和理解的学生信息列表
        💡 列表展示流程：
        - 清屏并显示学生列表标题
        - 打印表头和分隔线
        - 遍历学生列表，格式化输出每个学生的信息
        - 打印结束分隔线
        :param students: 学生对象列表
        :return: None
        """
        print("\n" + "=" * 100)
        print(f"{'学号':<12} {'姓名':<8} {'年龄':<4} {'性别':<4} {'专业':<15} {'班级':<10} {'电话':<12} {'邮箱':<20}")
        print("-" * 100)

        for student in students:
            print(f"{student.student_id:<12} {student.name:<8} {student.age:<4} {student.gender:<4} "
                  f"{student.major:<15} {student.class_name:<10} {student.phone:<12} {student.email:<20}")

        print("=" * 100)

    def show_statistics(self):
        """
        显示统计信息（选做）
        🎓 教学要点：
        - 业务逻辑调用：获取统计信息
        - 数据展示：格式化输出统计结果
        - 用户体验：清晰的统计信息展示
        💡 统计流程：
        - 清屏并显示统计信息标题
        - 调用服务层的get_statistics方法获取统计数据
        - 如果有统计数据，格式化输出总学生数、按性别和专业统计
        - 如果没有统计数据，显示提示信息
        - 提供返回主菜单的选项
        :return: None
        """
        self.clear_screen()
        print("统计信息")

        stats = self.service.get_statistics()

        if stats:
            print(f"\n总学生数: {stats['total_count']}")

            print(f"\n按性别统计:")
            for gender, count in stats['gender_stats'].items():
                print(f"  {gender}: {count} 人")

            print(f"\n按专业统计:")
            for major, count in stats['major_stats'].items():
                print(f"  {major}: {count} 人")
        else:
            print("获取统计信息失败！")

        input("\n按回车键继续...")


def main():
    """主函数"""
    try:
        system = StudentManagementSystem()
        system.run()
    except KeyboardInterrupt:
        print("\n\n程序被用户中断，正在退出...")
    except Exception as e:
        print(f"\n程序出现错误: {str(e)}")
        print("请联系系统管理员。")


if __name__ == "__main__":
    main()
